package motodev.app;

import java.io.IOException;

import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.TiledLayer;
import javax.microedition.midlet.MIDlet;


public class MyGameCanvas extends GameCanvas implements Runnable {
	
	// Reference 
	MIDlet midlet;
	
	// Board constants
	private static final int WHITE = 1;
	private static final int CURSOR = 2;
	private static final int RED = 3;
	private static final int BLACK = 4;
	
	// Message constants
	private static final int BLACK_TURN = 1;
	private static final int RED_TURN = 2;
	private static final int YOU_WIN = 3;
	private static final int TIE_GAME = 4;
	private static final int YOU_LOSE = 5;
	
	// Image data
	private Image backgroundImg;
	private Image messageImg;
	private TiledLayer message;
	private TiledLayer background;
	
	// Game variables
	private int currentPlayer = BLACK;
	private int[][] grid = {{WHITE, WHITE, WHITE, WHITE, WHITE},
							{WHITE, WHITE, WHITE, WHITE, WHITE},
							{WHITE, WHITE, WHITE, WHITE, WHITE},
							{WHITE, WHITE, WHITE, WHITE, WHITE},
							{WHITE, WHITE, WHITE, WHITE, WHITE}};
	private int[] columnPos = {4, 4, 4, 4, 4};
	// The column the cursor is in
	public int cursorPos = 2;
	public boolean gameFinished = false;
	public boolean myTurn = true;

	/**
	 * Canvas constructor
	 */
	protected MyGameCanvas(MIDlet midlet) {
		super(true);
		this.midlet = midlet;
	}

	/**
	 * Initializes the game state. Creates the board.
	 */
	public void start() {
		gameFinished = false;
		// Load background image
		try {
			backgroundImg = Image.createImage("/background.png");
		} catch (IOException ioex) { 
			System.err.println(ioex); 
		}
		
		// Load message image
		try {
			messageImg = Image.createImage("/message.png");
		} catch (IOException ioex) { 
			System.err.println(ioex); 
		}
		
		// Create tiled layer for background
		background = new TiledLayer(5, 5, backgroundImg, 32, 32);
		int[] cells = {WHITE, WHITE, WHITE, WHITE, WHITE,
						WHITE, WHITE, WHITE, WHITE, WHITE,
						WHITE, WHITE, WHITE, WHITE, WHITE,
						WHITE, WHITE, WHITE, WHITE, WHITE,
						WHITE, WHITE, WHITE, WHITE, WHITE};	
		// Set the background with the images
		for (int i = 0; i < cells.length; i++) {
			int column = i % 5;
			int row = (i - column) / 5;
			background.setCell(column, row, cells[i]);
		}
		// Set initial cursor position
		background.setCell(cursorPos, columnPos[cursorPos], CURSOR);
		// Center background
		background.setPosition((getWidth() - 160)/2, 20);
		
		
		// Create tiled layer for message
		message = new TiledLayer(1, 1, messageImg, 160, 32);
		// Display message 'Black's turn'
		message.setCell(0, 0, BLACK_TURN);
		// Center message tile at the bottom of the screen
		message.setPosition((getWidth() - 160)/2, (getHeight() - 64));

		// Start a thread
		Thread runner = new Thread(this);
		runner.start();
	}

	/**
	 * Main program run loop. Runs the game until a winner 
	 * is decided or a tie is reached.
	 */
	public void run() {
		while(!gameFinished) {
			
			// Only gather input if it is the user's turn
			if (myTurn) {
				checkUserInput(); 
				updateGameScreen(getGraphics());
				// control the rate at which screen updates are done
			}
				
			try { Thread.sleep(200); } 
			catch (InterruptedException e) { e.printStackTrace(); }
			
		}
		updateGameScreen(getGraphics());
		((Connect4) midlet).gameOver();
	}

	/**
	 * Draws all images on the screen. Updates after each move.
	 */
	private void updateGameScreen(Graphics g) {
		// Draw board
		g.setColor(0xffffff);
		g.fillRect(0, 0, getWidth(), getHeight());
		background.paint(g);	
		// Draw message
		message.paint(g);

		flushGraphics();
	}

	/**
	 * Executes game logic based on pressed keys. User entered data.
	 */
	private void checkUserInput() {
		
		if (!gameFinished) {
			// get the state of keys
			int keyState = getKeyStates();
	
			if ((keyState & LEFT_PRESSED) != 0) {
				if (cursorPos > 0) {
					
					// When top row of next left is not reached (normal case)
					if (columnPos[cursorPos-1] >= 0) {
						background.setCell(cursorPos, columnPos[cursorPos], WHITE);
						cursorPos--;
						background.setCell(cursorPos, columnPos[cursorPos], CURSOR);
					
					// When top row of next left column is reached (special case)
					} else {
						background.setCell(cursorPos, columnPos[cursorPos], WHITE);
						moveCursorLeftToNextEmptySpace();
						background.setCell(cursorPos, columnPos[cursorPos], CURSOR);
					}
				}
				
				System.out.println("cursorPos: " + cursorPos+ "  ColumnPos["+cursorPos+"]: "+columnPos[cursorPos]);
				
			} else if ((keyState & RIGHT_PRESSED) != 0) {
				if (cursorPos < 4) {
					
					// When top row of next right is not reached (normal case)
					if (columnPos[cursorPos+1] >= 0) {
						background.setCell(cursorPos, columnPos[cursorPos], WHITE);
						cursorPos++;
						background.setCell(cursorPos, columnPos[cursorPos], CURSOR);
						
					// When top row of next right column is reached (special case)
					} else {
						background.setCell(cursorPos, columnPos[cursorPos], WHITE);
						moveCursorRightToNextEmptySpace();
						background.setCell(cursorPos, columnPos[cursorPos], CURSOR);
					}
					
				}
				
				System.out.println("cursorPos: " + cursorPos+ "  ColumnPos["+cursorPos+"]: "+columnPos[cursorPos]);
				
			} else if ((keyState & FIRE_PRESSED) != 0) {
				
				// Make your move
				makeMove(cursorPos);
				System.out.println("cursorPos: " + cursorPos+ "  ColumnPos["+cursorPos+"]: "+columnPos[cursorPos]);
				
				// TODO Encrypt move and send to opponent
				byte [] fullMessage = new byte[100];
				// Game messages are prefixed with 'm'
				fullMessage[0] = 'm';
				// Encrypt the user's move
				byte [] encryptedMove = {0};
				// Copy encryptedMove into full message byte array and then send it
				System.arraycopy(encryptedMove, 0, fullMessage, 1, encryptedMove.length);
				RMS.send_cmd(fullMessage);
			}
		}
	}
	
	/**
	 * Moves the cursor to the left if there is a spot to the left.
	 */
	public void moveCursorLeftToNextEmptySpace() {
		if (cursorPos > 0) {
			cursorPos--;
		} else {
			cursorPos = 4;
		}
		while (columnPos[cursorPos] < 0) {
			if (cursorPos > 0) {
				cursorPos--;
			} else {
				cursorPos = 4;
			}
		}
	}
	
	/**
	 * Moves the cursor right if there is a spot to the right.
	 */
	public void moveCursorRightToNextEmptySpace() {
		cursorPos = (cursorPos + 1) % 5;
		while (columnPos[cursorPos] < 0) {
			cursorPos = (cursorPos + 1) % 5;
		}
	}

	/**
	 * Updates the game board based on the move that the player made.
	 * Checks for a winner.
	 * @param position Position that the player placed move.
	 */
	private void makeMove(int position) {
		
		// Set the global variable 'cursorPos' to the opponent's position
		if (!myTurn) {
			cursorPos = position;
		}
		
		// Mark selected index for current player
		grid[columnPos[cursorPos]][cursorPos] = currentPlayer;
		background.setCell(cursorPos, columnPos[cursorPos], currentPlayer);
		
		// Check for victory
		if (Board.checkWinner(background, columnPos[cursorPos], cursorPos)) {
			gameFinished = true;
			// If player won the game
			if (myTurn) {
				message.setCell(0, 0, YOU_WIN);
			
			// If player lost the game
			} else {
				message.setCell(0, 0, YOU_LOSE);
			}
		}
		
		// Update the chosen column's position
		columnPos[cursorPos]--;
		
		// Check for tie game (when all spaces filled without a victory)
		if (	columnPos[cursorPos] < 0 &&
				columnPos[(cursorPos + 1 ) % 5] < 0 &&
				columnPos[(cursorPos + 2 ) % 5] < 0 &&
				columnPos[(cursorPos + 3 ) % 5] < 0 &&
				columnPos[(cursorPos + 4 ) % 5] < 0  &&
				!gameFinished) {
			
			// Tie game
			System.out.println("TIE GAME");
			// Display message 'Tie game'
			message.setCell(0, 0, TIE_GAME);
			gameFinished = true;
			
		}
		
		// Continue if game is not finished
		if (!gameFinished) {
			
			// Update cursor after turn
			if (columnPos[cursorPos] >= 0) {
				// Set the new cursor
				background.setCell(cursorPos, columnPos[cursorPos], CURSOR);
			
			// Top space in column has just been filled
			} else {
				// Scan for next empty space
				moveCursorRightToNextEmptySpace();
				background.setCell(cursorPos, columnPos[cursorPos], CURSOR);
			}
			
			// Switch turns
			if (currentPlayer == BLACK ) {
				currentPlayer = RED;
				// Display message 'Red's turn'
				message.setCell(0, 0, RED_TURN);
			} else {
				currentPlayer = BLACK;
				// Display message 'Black's turn'
				message.setCell(0, 0, BLACK_TURN);
			}
			myTurn = !myTurn;
			
			// Remove the cursor from display if user is done with their turn
			if (!myTurn) {
				background.setCell(cursorPos, columnPos[cursorPos], WHITE);
			}
		}
	}
	
	public void opponentMove(int opponentCursorPos) {	
		makeMove(opponentCursorPos);
	}
}
